package com.wfh.mianshiji.tts;

import com.alibaba.dashscope.aigc.multimodalconversation.AudioParameters;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.wfh.mianshiji.tts.model.SseMultiData;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;

/**
 * @author fenghuanwang
 */
@Slf4j
@Service
public class TtsStreamingService {

    @Value("${tts.ali.model}") // 应为 "qwen3-tts-flash"
    private String model;

    @Value("${tts.ali.voice}") // 如 "CHERRY"
    private String voice;

    @Value("${spring.ai.dashscope.api-key}")
    private String apiKey;

    @Value("${minio.config.bucket}")
    private String bucketName;

    @Resource
    private MinioClient minioClient;

    // 更健壮的句子结束判断
    private static final Pattern SENTENCE_END_PATTERN = Pattern.compile(".*[。！？.!?…]$");

    public Flux<SseMultiData> streamTextToAudio(Flux<String> textFlux) {
        Sinks.Many<SseMultiData> sink = Sinks.many().unicast().onBackpressureBuffer();
        StringBuilder buffer = new StringBuilder();
        ByteArrayOutputStream fullAudioBuffer = new ByteArrayOutputStream();
        AtomicBoolean completed = new AtomicBoolean(false);

        textFlux
                .doOnNext(token -> {
                    if (token == null || token.trim().isEmpty()){
                        return;
                    }
                    String clean = sanitizeText(token);
                    if (clean.isEmpty()) {
                        return;
                    }

                    buffer.append(clean);
                    String current = buffer.toString().trim();

                    if (isCompleteSentence(current)) {
                        processSentence(current, fullAudioBuffer, sink);
                        buffer.setLength(0); // 清空
                    }
                })
                .doOnComplete(() -> {
                    String remaining = buffer.toString().trim();
                    if (!remaining.isEmpty()) {
                        processSentence(remaining + "。", fullAudioBuffer, sink);
                    }
                    if (completed.compareAndSet(false, true)) {
                        uploadFullAudioToMinio(fullAudioBuffer);
                        sink.tryEmitNext(SseMultiData.done());
                        sink.tryEmitComplete();
                    }
                })
                .doOnError(error -> {
                    log.error("文本流异常", error);
                    if (completed.compareAndSet(false, true)) {
                        sink.tryEmitError(error);
                    }
                })
                .subscribe();

        return sink.asFlux()
                .doFinally(signalType -> {
                    try {
                        fullAudioBuffer.close();
                    } catch (Exception e) {
                        log.warn("关闭音频缓冲区失败", e);
                    }
                });
    }

    /**
     * 使用官方推荐的 MultiModalConversation 方式调用 TTS
     */
    private void processSentence(String sentence, ByteArrayOutputStream fullAudioBuffer, Sinks.Many<SseMultiData> sink) {
        if (sentence == null || sentence.trim().isEmpty()) {
            return;
        }
        ByteArrayOutputStream sentenceAudioBuffer = new ByteArrayOutputStream(); // 用于累积当前句子的所有 chunk
        try {
            MultiModalConversationParam param = MultiModalConversationParam.builder()
                    .apiKey(apiKey)
                    .model(model)
                    .text(sentence)
                    .voice(AudioParameters.Voice.valueOf(voice))
                    .languageType("Chinese")
                    .build();

            MultiModalConversation conv = new MultiModalConversation();
            conv.streamCall(param)
                    .blockingForEach(result -> {
                        try {
                            String base64Audio = result.getOutput().getAudio().getData();
                            if (base64Audio == null || base64Audio.isEmpty()) {
                                return; // 忽略空 chunk
                            }
                            base64Audio = base64Audio.replaceAll("\\s", "");
                            byte[] audioBytes = Base64.getDecoder().decode(base64Audio);
                            if (audioBytes.length > 0) {
                                sentenceAudioBuffer.write(audioBytes);
                            }
                        } catch (Exception e) {
                            log.warn("处理 TTS chunk 失败", e);
                        }
                    });
            // ✅ 所有 chunk 处理完毕，一次性 emit
            byte[] finalAudio = sentenceAudioBuffer.toByteArray();
            if (finalAudio.length > 0) {
                // log.info("✅ 句子 TTS 完成: '{}', 总音频长度: {} 字节", sentence, finalAudio.length);
                sink.tryEmitNext(new SseMultiData(sentence, finalAudio));
                synchronized (fullAudioBuffer) {
                    fullAudioBuffer.write(finalAudio);
                }
/*                // ✅ 3. 【测试用】实时播放整句话（异步，不阻塞）
                new Thread(() -> {
                    AudioFormat format = new AudioFormat(
                            AudioFormat.Encoding.PCM_SIGNED,
                            24000, // 采样率
                            16,    // 位深
                            1,     // 单声道
                            2,     // 帧大小 = 16/8 * 1
                            24000, // 帧速率
                            false  // 小端序（DashScope 通常为小端）
                    );
                    playAudio(finalAudio, format);
                }, "TTS-Player-" + System.currentTimeMillis()).start();*/
            } else {
                log.warn("❌ 句子无有效音频: {}", sentence);
            }
        } catch (Exception e) {
            log.error("TTS 调用失败（句子: {}）", sentence, e);
        }
    }

    private boolean isCompleteSentence(String text) {
        if (text == null || text.length() < 2) {
            return false;
        }
        // 必须包含中文/英文字符，且以句尾标点结尾
        return text.matches(".*[\\u4e00-\\u9fa5a-zA-Z0-9].*")
                && SENTENCE_END_PATTERN.matcher(text).matches();
    }
    private void uploadFullAudioToMinio(ByteArrayOutputStream fullAudioBuffer) {
        try {
            byte[] audioBytes = fullAudioBuffer.toByteArray();
            if (audioBytes.length == 0) {
                // log.warn("音频为空，跳过上传");
                return;
            }

            String objectName = "tts/" +
                    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd/HH")) +
                    "/" + System.currentTimeMillis() + ".mp3";

            ByteArrayInputStream inputStream = new ByteArrayInputStream(audioBytes);
            PutObjectArgs putArgs = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(inputStream, audioBytes.length, -1)
                    .contentType("application/octet-stream")
                    .build();

            minioClient.putObject(putArgs);
            log.info("TTS 音频已上传至 MinIO: {}/{}", bucketName, objectName);

        } catch (Exception e) {
            log.error("上传 TTS 音频到 MinIO 失败", e);
        }
    }

    private static String sanitizeText(String input) {
        if (input == null){
            return "";
        }
        return input
                .replaceAll("[\\p{C}\\u200B-\\u200D\\uFEFF\\u00AD]", "") // 清除控制字符
                .replaceAll("[\\*\\_\\#\\`\\<\\>\\[\\]\\(\\)\\|\\{\\}]+", "")
                .replaceAll("\\s+", " ")
                .trim();
    }

   /* private void playAudio(byte[] audioData, AudioFormat format) {
        try {
            // 检查系统是否支持该音频格式
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
            if (!AudioSystem.isLineSupported(info)) {
                // System.err.println("❌ 不支持的音频格式: " + format);
                return;
            }

            // 打开音频输出设备（扬声器）
            try (SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info)) {
                line.open(format);
                line.start(); // 开始播放

                // 将音频数据写入播放缓冲区
                line.write(audioData, 0, audioData.length);

                // 等待所有音频播放完毕
                line.drain();

                // 停止并关闭
                line.stop();
            }

            System.out.println("✅ 音频播放完成");

        } catch (Exception e) {
            System.err.println("💥 播放音频时出错: " + e.getMessage());
            e.printStackTrace();
        }
}*/
}